package eventbus

import (
	"context"
	"strings"

	"gitee.com/linxing_3/sr-core/plugins/mq"
)

type MsgPlatform string

const (
	MsgPlatformDefault MsgPlatform = "default"
	MsgPlatformRabbit  MsgPlatform = "rabbit"
	MsgPlatformRedis   MsgPlatform = "redis"
	MsgPlatformMqtt    MsgPlatform = "mqtt"
	MsgPlatformKafka   MsgPlatform = "kafka"
)

type SubscribeCallback func(ctx context.Context, msg *Message) error
type MessageOption func(*Message)

func WithMsgTopic(val string) MessageOption {
	return func(m *Message) { m.Topic = val }
}
func WithMsgPlatform(val MsgPlatform) MessageOption {
	return func(m *Message) { m.Platform = val }
}
func WithMsgQos(val int) MessageOption {
	return func(m *Message) { m.Qos = val }
}
func WithMsgWait() MessageOption {
	return func(m *Message) { m.Wait = true }
}
func WithMsgBody(val any) MessageOption {
	// bd, _ := json.Marshal(val)
	return func(m *Message) { m.Body = val }
}
func WithMsgMetaKV(key, val string) MessageOption {
	return func(m *Message) { m.Meta[key] = val }
}
func WithMsgMeta(meta MsgMeta) MessageOption {
	return func(m *Message) { m.Meta = meta }
}

func WithMsgToMQ() MessageOption {
	return func(m *Message) { m.SyncToMQIfNoSubs = true }
}

func NewMessage(opts ...MessageOption) *Message {
	msg := &Message{
		Platform: MsgPlatformDefault,
		Qos:      0,
		Wait:     false,
		Meta:     make(map[string]string),
	}
	for _, opt := range opts {
		opt(msg)
	}
	return msg
}

type MsgMeta map[string]string

func NewMsgMeta(val map[string]string) MsgMeta {
	m := make(MsgMeta)
	for k, v := range val {
		m[strings.ToLower(k)] = v
	}
	return m
}

func (m MsgMeta) Get(key string) string {
	v, _ := m.GetE(key)
	return v
}

func (m MsgMeta) GetE(key string) (string, bool) {
	key = strings.ToLower(key)
	val, ok := m[key]
	return val, ok
}

type Message struct {
	Topic            string       // 主题
	TraceId          string       // 跟踪ID
	Platform         MsgPlatform  // 平台
	Qos              int          // only mqtt
	Wait             bool         // 是否等待订阅消息处理完成
	Body             any          // 消息体
	Meta             MsgMeta      // 元数据
	SyncToMQIfNoSubs bool         // 如果没有订阅者，是否同步到MQ
	MQ               mq.IMsgQueue // 消息队列
}

type IEventSubscriber interface {
	// 启动消费者
	Subscribe(provider IEventBusProvider) error
}

type IEventBusProvider interface {
	SetMQ(mq mq.IMsgQueue)

	// 发布事件
	Publish(ctx context.Context, msg *Message) error

	// 异步发布事件
	AsyncPublish(ctx context.Context, msg *Message) error

	// 订阅事件
	Subscribe(topic string, handler SubscribeCallback) (string, error)
}
